package service

import (
	"context"
	"encoding/json"
	"fmt"
	"server/internal/app/dto"
	"server/internal/app/model"
	"server/internal/app/repository"
	"server/internal/core/store"
	"server/pkg/utils"
	"slices"
	"time"
)

type AdminRbacService struct {
	adminRepo          *repository.SysAdminRepository
	roleRepo           *repository.SysRoleRepository
	permissionRepo     *repository.SysPermissionRepository
	adminRoleRepo      *repository.SysAdminRoleRepository
	rolePermissionRepo *repository.SysRolePermissionRepository
	adminInfoKey       string
}

func NewAdminRbacService() *AdminRbacService {
	return &AdminRbacService{
		adminInfoKey:       "admin:info:%d",
		adminRepo:          repository.NewSysAdminRepository(),
		roleRepo:           repository.NewSysRoleRepository(),
		permissionRepo:     repository.NewSysPermissionRepository(),
		adminRoleRepo:      repository.NewSysAdminRoleRepository(),
		rolePermissionRepo: repository.NewSysRolePermissionRepository(),
	}
}

func (s *AdminRbacService) GetAdminInfo(ctx context.Context, adminID uint, cache bool) (*dto.AdminProfile, error) {
	var adminInfo *dto.AdminProfile
	if cache {
		data := store.Redis.Get(ctx, fmt.Sprintf(s.adminInfoKey, adminID)).String()
		if data != "" {
			if err := json.Unmarshal([]byte(data), &adminInfo); err == nil {
				return adminInfo, nil
			}
		}
	}

	admin, err := s.adminRepo.GetByID(ctx, adminID)
	if err != nil {
		return nil, err
	}
	//获取权限
	rolePermissions, err := s.adminRepo.GetAdminPermissions(ctx, adminID)
	if err != nil {
		return nil, err
	}

	adminInfo = &dto.AdminProfile{
		ID:       admin.ID,
		Username: admin.Username,
		Nickname: admin.Nickname,
		Avatar:   admin.Avatar,
		Email:    admin.Email,
		Status:   int8(admin.Status),
	}

	//去重
	roleMap := make(map[string]bool)
	permissionsMap := make(map[string]bool)
	for _, rolePermission := range rolePermissions {
		if _, ok := roleMap[rolePermission.RoleCode]; !ok {
			adminInfo.Roles = append(adminInfo.Roles, dto.AdminRole{
				Code: rolePermission.RoleCode,
				Name: rolePermission.RoleName,
			})
			roleMap[rolePermission.RoleCode] = true
		}

		if _, ok := permissionsMap[rolePermission.PermissionPath]; !ok {
			switch rolePermission.PermissionType {
			case model.PermissionTypeApi:
				adminInfo.PermissionsApi = append(adminInfo.PermissionsApi, rolePermission.PermissionPath)
			case model.PermissionTypeMenu:
				adminInfo.PermissionsMenu = append(adminInfo.PermissionsMenu, rolePermission.PermissionPath)
			case model.PermissionTypeButton:
				adminInfo.PermissionsButton = append(adminInfo.PermissionsButton, rolePermission.PermissionPath)
			}
			permissionsMap[rolePermission.PermissionPath] = true
		}

		//超级管理员,写死处理
		if !adminInfo.IsSuper && rolePermission.RoleCode != "admin" {
			adminInfo.IsSuper = true
		}
	}

	//缓存
	store.Redis.Set(ctx, fmt.Sprintf(s.adminInfoKey, adminID), utils.Json(adminInfo), 10*time.Minute).Err()
	return adminInfo, nil
}

// 检查权限
func (s *AdminRbacService) CheckPermission(ctx context.Context, adminID uint, permissionType model.PermissionType, permissionPath string) bool {
	adminInfo, err := s.GetAdminInfo(ctx, adminID, true)
	if err != nil {
		return false
	}
	if adminInfo.IsSuper {
		return true
	}

	permissions := make([]string, 0)
	switch permissionType {
	case model.PermissionTypeApi:
		permissions = adminInfo.PermissionsApi
	case model.PermissionTypeMenu:
		permissions = adminInfo.PermissionsMenu
	case model.PermissionTypeButton:
		permissions = adminInfo.PermissionsButton
	}

	return slices.Contains(permissions, permissionPath)
}

// admin 列表
func (s *AdminRbacService) GetAdminList(ctx context.Context, param *dto.PaginationRequest) (*dto.PaginationResponse[*dto.AdminProfile], error) {
	adminList, err := s.adminRepo.List(ctx, param)
	if err != nil {
		return nil, err
	}

	// 获取角色
	roleList, err := s.adminRoleRepo.All(ctx)
	if err != nil {
		return nil, err
	}
	adminRoleMap := make(map[uint][]uint)
	for _, role := range roleList {
		if _, ok := adminRoleMap[role.AdminID]; !ok {
			adminRoleMap[role.AdminID] = make([]uint, 2)
		}
		adminRoleMap[role.AdminID] = append(adminRoleMap[role.AdminID], role.RoleID)
	}

	// 获取角色信息
	roleInfoList, err := s.roleRepo.All(ctx)
	if err != nil {
		return nil, err
	}
	roleMap := make(map[uint]*model.SysRole)
	for _, roleInfo := range roleInfoList {
		roleMap[roleInfo.ID] = &roleInfo
	}

	adminProfiles := make([]*dto.AdminProfile, 0)
	for _, admin := range adminList.Items {
		adminProfile := &dto.AdminProfile{
			ID:       admin.ID,
			Username: admin.Username,
			Nickname: admin.Nickname,
			Email:    admin.Email,
			Status:   int8(admin.Status),
			Roles:    make([]dto.AdminRole, 0),
		}
		if adminRoles, ok := adminRoleMap[admin.ID]; ok {
			for _, roleID := range adminRoles {
				roleInfo := roleMap[roleID]
				if roleInfo != nil {
					adminProfile.Roles = append(adminProfile.Roles, dto.AdminRole{
						Code:   roleInfo.Code,
						Name:   roleInfo.Name,
						Status: int8(roleInfo.Status),
					})
				}
			}
		}
		adminProfiles = append(adminProfiles, adminProfile)
	}
	return &dto.PaginationResponse[*dto.AdminProfile]{
		Total:    adminList.Total,
		Page:     adminList.Page,
		PageSize: adminList.PageSize,
		Items:    adminProfiles,
	}, nil
}

func (s *AdminRbacService) UpdateStatus(ctx context.Context, adminID uint, status int8) error {
	return s.adminRepo.Update(ctx, adminID, map[string]any{"status": status})
}

// 角色列表
func (s *AdminRbacService) GetRoleList(ctx context.Context) ([]model.SysRole, error) {
	roleList, err := s.roleRepo.All(ctx)
	return roleList, err
}

// 创建角色
func (s *AdminRbacService) CreateRole(ctx context.Context, request *dto.CreateRoleRequest) error {
	return s.roleRepo.Create(ctx, &model.SysRole{
		Name:   request.Name,
		Code:   request.Code,
		Status: request.Status,
	})
}

// 更新角色
func (s *AdminRbacService) UpdateRole(ctx context.Context, request *dto.UpdateRoleRequest) error {
	return s.roleRepo.Update(ctx, request.ID, map[string]any{
		"name":   request.Name,
		"code":   request.Code,
		"status": request.Status,
	})
}

// 删除角色
func (s *AdminRbacService) DeleteRole(ctx context.Context, request *dto.DeleteRoleRequest) error {
	return s.roleRepo.Delete(ctx, request.ID)
}

// 权限列表
func (s *AdminRbacService) GetPermissionList(ctx context.Context) ([]model.SysPermission, error) {
	return s.permissionRepo.All(ctx)
}

// 创建权限
func (s *AdminRbacService) CreatePermission(ctx context.Context, request *dto.CreatePermissionRequest) error {
	return s.permissionRepo.Create(ctx, &model.SysPermission{
		Name:   request.Name,
		Path:   request.Path,
		Type:   request.Type,
		Status: request.Status,
	})
}

// 更新权限
func (s *AdminRbacService) UpdatePermission(ctx context.Context, request *dto.UpdatePermissionRequest) error {
	return s.permissionRepo.Update(ctx, request.ID, map[string]any{
		"name":   request.Name,
		"status": request.Status,
		"path":   request.Path,
		"type":   request.Type,
	})
}

// 删除权限
func (s *AdminRbacService) DeletePermission(ctx context.Context, request *dto.DeletePermissionRequest) error {
	return s.permissionRepo.Delete(ctx, request.ID)
}

// 分配权限
func (s *AdminRbacService) AssignRolePermission(ctx context.Context, request *dto.AssignRolePermissionRequest) error {
	return s.rolePermissionRepo.AssignPermission(ctx, request.RoleID, request.PermissionIDs...)
}

// 分配管理员角色
func (s *AdminRbacService) AssignAdminRole(ctx context.Context, request *dto.AssignAdminRoleRequest) error {
	return s.adminRoleRepo.AssignRole(ctx, request.AdminID, request.RoleIDs...)
}
